﻿
Imports std
Imports blobs_nodes_property = osi.fs.cached_vector_int64_property
Imports lock_t = lock(Of locks.simplelock)

Partial Public Class node
    Private Shared ReadOnly next_blob_id As next_id = Nothing

    Partial Private Class internal_property_names
        Public Const blobs As String = "blb"
    End Class

    Private Shared Function next_blob(ByRef key As String) As Int64
        Dim id As Int64 = 0
        id = next_blob_id.next()
        key = create_blob_key(id)
        Return id
    End Function

    Private Function set_last_write_time(ByVal ec As eventComb) As eventComb
        assert(Not ec Is Nothing)
        Return New eventComb(Function() As Boolean
                                 Return waitfor(ec) AndAlso
                                        goto_next()
                             End Function,
                             Function() As Boolean
                                 Return ec.end_result() AndAlso
                                        waitfor(set_last_write_time()) AndAlso
                                        goto_end()
                             End Function)
    End Function

    Public Function blobs(ByVal output As pointer(Of vector(Of Int64))) As eventComb
        Return p.get_data(internal_property_names.blobs, output)
    End Function

    Private Function add_blob(ByVal id As Int64) As eventComb
        Return set_last_write_time(p.create_get_set_data(Of vector(Of Int64), blobs_nodes_property) _
                                                        (internal_property_names.blobs,
                                                         add_vector_int64(id)))
    End Function

    Private ReadOnly pending_blobs As map(Of String, Int64) = Nothing
    Private pending_blobs_lock As lock_t

    Public Function add_blob(ByRef key As String) As Boolean
        Dim id As Int64 = 0
        Dim k As String = Nothing
        Return pending_blobs_lock.locked(Function() As Boolean
                                             If pending_blobs.size() > max_pending_blob_count Then
                                                 Return False
                                             Else
                                                 id = next_blob(k)
                                                 assert(pending_blobs.find(k) = pending_blobs.end())
                                                 pending_blobs(k) = id
                                                 Return True
                                             End If
                                         End Function) AndAlso
               eva(key, k)
    End Function

    Public Function confirm_blob(ByVal key As String) As eventComb
        Return New eventComb(Function() As Boolean
                                 Dim id As Int64 = 0
                                 Return pending_blobs_lock.locked(
                                            Function() As Boolean
                                                Dim it As map(Of String, Int64).iterator = Nothing
                                                it = pending_blobs.find(key)
                                                If it = pending_blobs.end() Then
                                                    Return False
                                                Else
                                                    id = (+it).second
                                                    Return True
                                                End If
                                            End Function) AndAlso
                                        waitfor(add_blob(id)) AndAlso
                                        goto_end()
                             End Function)
    End Function

    Public Function cancel_blob(ByVal key As String) As Boolean
        Return pending_blobs_lock.locked(Function() pending_blobs.erase(key))
    End Function

    Public Delegate Function add_blob_d(ByVal key As String) As eventComb

    Public Function add_blob(ByVal d As add_blob_d) As eventComb
        assert(Not d Is Nothing)
        Dim ec As eventComb = Nothing
        Dim key As String = Nothing
        Return New eventComb(Function() As Boolean
                                 If add_blob(key) Then
                                     ec = d(key)
                                     Return waitfor(ec) AndAlso
                                            goto_next()
                                 Else
                                     Return False
                                 End If
                             End Function,
                             Function() As Boolean
                                 If ec.end_result() Then
                                     ec = confirm_blob(key)
                                     Return waitfor(ec) AndAlso
                                            goto_next()
                                 Else
                                     Return cancel_blob(key) AndAlso
                                            False
                                 End If
                             End Function,
                             Function() As Boolean
                                 Return ec.end_result() AndAlso
                                        goto_end()
                             End Function)
    End Function
End Class
